#include <iostream>
#include "common.h"
#include "NesCartridge.h"
#include "mapper/MapperFactory.h"

NesCartridge::NesCartridge(Famicom * fc):famicom(fc)
{
}

NesCartridge::~NesCartridge()
{
	Release();
}

void NesCartridge::Reset() {
	this->mapper->Reset();
	famicom->ppu->SwitchMirroring(mRom.isVmirroring ? Mirror::VERTICAL : Mirror::HORIZONTAL);
}

Rom* NesCartridge::GetRom() {
	return &mRom;
}

bool NesCartridge::loadedrom() {
	return mLoadedrom;
}


uint8_t NesCartridge::PRG_num()
{
	return mRom.prg16kbCount;
}

/// <summary>
/// 
/// </summary>
void NesCartridge::Release() {
	if (mRom.prgrom != nullptr)
		free(mRom.prgrom);
	if (mRom.chrrom != nullptr)
		free(mRom.chrrom);
	if (this->mapper != nullptr)
		delete this->mapper;
}
/// <summary>
///
/// </summary>
/// <param name="rom"></param>
/// <param name="size"></param>
/// <returns></returns>
int NesCartridge::LoadRom(uint8_t* const rom, const uint32_t size) {

	Release();


	if (size != mRom.size)
		return false;

	if ((mRom.prgrom = (uint8_t*)malloc(mRom.prgRomSize)) == nullptr)
	{
		assert(!"malloc failed");
		return false;
	}
	memcpy(mRom.prgrom, rom, mRom.prgRomSize);
	if (!mRom.isChrRAM) {
		if ((mRom.chrrom = (uint8_t*)malloc(mRom.chrRomSize)) == nullptr)
		{
			free(mRom.prgrom);
			assert(!"malloc failed");
			return false;
		}
		memcpy(mRom.chrrom, rom + mRom.prgRomSize, mRom.chrRomSize);
	}
	else {
		if ((mRom.chrrom = (uint8_t*)malloc(8192)) == nullptr)
		{
			free(mRom.prgrom);
			assert(!"malloc failed");
			return false;
		}
		mRom.chrRomSize = 8192;
		mRom.chr8kbCount = 1;
		memset(mRom.chrrom, 0, mRom.chrRomSize);
	}

	this->mapper = MapperFactory::Factory(famicom,mRom.mapperNumber);
	if (this->mapper == nullptr) {
		assert(!"Mapper error");
		return false;
	}
	mLoadedrom = true;
	this->mapper->LoadRom(&mRom);
	return true;
}

void NesCartridge::Save(SaveBundle* bundle)
{
	if (this->mapper != nullptr)
		this->mapper->Save(bundle);
}

void NesCartridge::Restore(SaveBundle* bundle)
{
	if (this->mapper != nullptr)
		this->mapper->Restore(bundle);
}

/// <summary>
/// 验证文件头
/// </summary>
/// <param name="header"></param>
/// <param name="hsize"></param>
/// <param name="psize"></param>
/// <returns></returns>
int NesCartridge::Validate(uint8_t* header, uint32_t hsize, uint32_t* psize)
{
	if (hsize != 16)
		return false;

	NesHeader* romhead = (NesHeader*)header;
	romhead->nes[3] = '\0';
	if (strcmp((char const*)romhead->nes, "NES") != 0) {
		return false;
	}
	mRom.prg16kbCount = romhead->PRGBankCount;
	mRom.chr8kbCount = romhead->CHRBankCount;

	mRom.prgrom = nullptr;
	mRom.chrrom = nullptr;

	mRom.isVmirroring = (romhead->flag1) & 0x1;
	mRom.hasBatteryBacked = (romhead->flag1 >> 1) & 0x1;
	mRom.hasTrainer = (romhead->flag1 >> 2) & 0x1;
	mRom.isFourScreen = (romhead->flag1 >> 3) & 0x1;

	mRom.version = (romhead->flag2 >> 2) & 0x3;

	
	uint8_t map = romhead->flag1 >> 4;
	map |= (romhead->flag2 & 0xf0);

	mRom.mapperNumber = map;

	mRom.prgRomSize = mRom.prg16kbCount * 16 * 1024;
	mRom.chrRomSize = mRom.chr8kbCount * 8 * 1024;

	mRom.size = mRom.prgRomSize + mRom.chrRomSize;

	mRom.isChrRAM = mRom.chr8kbCount == 0;


	*psize = mRom.size;
	DebugPrintf("Mapper:%d prg16kbCount:%d chr8kbCount:%d version:%d hasBatteryBacked:%d hasTrainer:%d\n",
		mRom.mapperNumber,
		mRom.prg16kbCount,
		mRom.chr8kbCount,
		mRom.version,
		mRom.hasBatteryBacked,
		mRom.hasTrainer);

	return true;
}

